﻿//ILogSource.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.Logging
{
	using System;
	using System.ComponentModel;

	using Ecng.Collections;
	using Ecng.Common;

	/// <summary>
	/// Интерфейс источника логов.
	/// </summary>
	public interface ILogSource : IDisposable
	{
		/// <summary>
		/// Уникальный идентификатор источника.
		/// </summary>
		Guid Id { get; }

		/// <summary>
		/// Имя источника.
		/// </summary>
		string Name { get; }

		/// <summary>
		/// Родительский источник логов.
		/// </summary>
		ILogSource Parent { get; }

		/// <summary>
		/// Уровень логирования для источника.
		/// </summary>
		LogLevels LogLevel { get; set; }

		/// <summary>
		/// Текущее время, которое будет передано в <see cref="LogMessage.Time"/>.
		/// </summary>
		DateTime CurrentTime { get; }

		/// <summary>
		/// Дочерние источники логов.
		/// </summary>
		INotifyList<ILogSource> Childs { get; }

		/// <summary>
		/// Событие нового отладочного сообщения.
		/// </summary>
		event Action<LogMessage> Log;
	}

	/// <summary>
	/// Базовая реализация <see cref="ILogSource"/>.
	/// </summary>
	/// <typeparam name="TParent">Тип родителя <see cref="ILogSource.Parent"/>.</typeparam>
	public abstract class BaseLogSource<TParent> : Disposable, ILogSource
	{
		/// <summary>
		/// Инициализировать <see cref="BaseLogSource{TParent}"/>.
		/// </summary>
		protected BaseLogSource()
		{
			_name = GetType().Name;
		}

		private Guid _id = Guid.NewGuid();

		/// <summary>
		/// Уникальный идентификатор источника.
		/// </summary>
		[Browsable(false)]
		public virtual Guid Id
		{
			get { return _id; }
			set { _id = value; }
		}

		private string _name;

		/// <summary>
		/// Название.
		/// </summary>
		[ReadOnly(true)]
		public virtual string Name
		{
			get { return _name; }
			set
			{
				if (value.IsEmpty())
					throw new ArgumentNullException("value");

				_name = value;
			}
		}

		/// <summary>
		/// Родитель.
		/// </summary>
		[Browsable(false)]
		public TParent Parent { get; set; }

		private LogLevels _logLevel = LogLevels.Inherit;

		/// <summary>
		/// Уровень логирования. По-умолчанию установлено в <see cref="LogLevels.Inherit"/>.
		/// </summary>
		public virtual LogLevels LogLevel
		{
			get { return _logLevel; }
			set { _logLevel = value; }
		}

		/// <summary>
		/// Установить коллекцию дочерних элементов, которые будут транслироваться в <see cref="ILogSource.Childs"/>.
		/// </summary>
		/// <typeparam name="TChild">Тип дочернего элемента.</typeparam>
		/// <param name="childs">Коллекция дочерних элементов.</param>
		protected void SetChilds<TChild>(INotifyList<TChild> childs)
		{
			_childs = new DuckTypedList<TChild, ILogSource>(childs, true);
			_childs.Added += ChildsOnAdded;
			_childs.Removed += ChildsOnRemoved;
			_childs.Inserted += ChildsOnInserted;
			_childs.Clearing += ChildsOnClearing;
			_childs.ForEach(child => child.Log += RaiseLog);
		}

		ILogSource ILogSource.Parent
		{
			get { return (ILogSource)Parent; }
		}

		private INotifyList<ILogSource> _childs;

		INotifyList<ILogSource> ILogSource.Childs
		{
			get { return _childs; }
		}

		/// <summary>
		/// Текущее время, которое будет передано в <see cref="LogMessage.Time"/>.
		/// </summary>
		[Browsable(false)]
		public virtual DateTime CurrentTime
		{
			get { return LoggingHelper.Now; }
		}

		private Action<LogMessage> _log;

		/// <summary>
		/// Событие нового отладочного сообщения.
		/// </summary>
		public event Action<LogMessage> Log
		{
			add { _log += value; }
			remove { _log -= value; }
		}

		/// <summary>
		/// Вызвать событие <see cref="ILogSource.Log"/>.
		/// </summary>
		/// <param name="message">Отладочное сообщение.</param>
		protected virtual void RaiseLog(LogMessage message)
		{
			if (message == null)
				throw new ArgumentNullException("message");

			if (message.Level < message.Source.LogLevel)
				return;

			//if (_log == null && Parent.IsNull())
			//	throw new InvalidOperationException("Родитель не подписан на дочерний лог.");

			_log.SafeInvoke(message);
		}

		private void ChildsOnClearing()
		{
			_childs.ForEach(child => child.Log -= RaiseLog);
		}

		private void ChildsOnInserted(int index, ILogSource child)
		{
			child.Log += RaiseLog;
		}

		private void ChildsOnRemoved(ILogSource child)
		{
			child.Log -= RaiseLog;
		}

		private void ChildsOnAdded(ILogSource child)
		{
			child.Log += RaiseLog;
		}

		/// <summary>
		/// Получить строковое представление источника.
		/// </summary>
		/// <returns>Строковое представление источника.</returns>
		public override string ToString()
		{
			return Name;
		}

		/// <summary>
		/// Освободить занятые ресурсы.
		/// </summary>
		protected override void DisposeManaged()
		{
			if (_childs != null)
			{
				_childs.ForEach(child => child.Log -= RaiseLog);

				_childs.Added -= ChildsOnAdded;
				_childs.Removed -= ChildsOnRemoved;
				_childs.Inserted -= ChildsOnInserted;
				_childs.Clearing -= ChildsOnClearing;

				_childs.DoDispose();
			}

			Parent = default(TParent);

			base.DisposeManaged();
		}
	}
}